﻿using ScottPlot;
using SkiaSharp;
using System;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.ScottPlotEx
{
    unsafe internal class WaterfallPlot_Up : WaterfallPlotAbs, IWaterfallPlot
    {


        public WaterfallPlot_Up(int dataWidth, int dataHeight, ScottPlot.Range dataRange, IColormap colormap, WaterfallPlotOptions options)
            : base(dataWidth, dataHeight, dataRange, colormap, PlotMoveDirection.Up, options)
        {

        }






        /// <summary>
        /// 追加一帧数据
        /// </summary>
        /// <param name="specData">频谱数据</param>
        public void AppendData(Span<double> specData)
        {
            Span<uint> argbs;
            Span<double> originValues;

            if (this._argsbWriteOffset >= this._argbsPointer.Length)
            {
                //已添加到尾部,需要重置
                var argbsDest = this._argbsPointer.GetSpan(0, this._imgPixs - this._fftLength);//取出起始数据
                var argbsSource = this._argbsPointer.GetSpan(this._imgPixs + this._fftLength, this._imgPixs - this._fftLength);//保留数据
                argbsSource.CopyTo(argbsDest);//将保留数据拷贝到起始

                if (this._cacheOriginValue)
                {
                    var originValueDest = this._originValuesPointer.GetSpan(0, this._imgPixs - this._fftLength);//取出保留的数据
                    var originValueSource = this._originValuesPointer.GetSpan(this._imgPixs + this._fftLength, this._imgPixs - this._fftLength);//将后末尾数据
                    originValueSource.CopyTo(originValueDest);//将保留数据拷贝到起始
                }

                this._argsbWriteOffset = this._imgPixs - this._fftLength;
            }

            argbs = this._argbsPointer.GetSpan(this._argsbWriteOffset, this._fftLength);
            if (this._cacheOriginValue)
            {
                originValues = this._originValuesPointer.GetSpan(this._argsbWriteOffset, this._fftLength);
            }
            else
            {
                originValues = this._originValuesPointer.GetSpan(0);
            }
            this._argsbWriteOffset += this._fftLength;

            if (this._flipHorizontally)
            {
                base.PrimitiveAppendData_Flip(specData, argbs, originValues);
            }
            else
            {
                base.PrimitiveAppendData(specData, argbs, originValues);
            }
            this._argbsIsUpdated = true;
        }

        /// <summary>
        /// 追加连续的多帧数据
        /// </summary>
        /// <param name="specData">多行频谱数据</param>
        /// <param name="framCount">数据帧数</param>
        public void AppendDatas(Span<double> specData, int framCount)
        {
            Span<uint> argbs;
            Span<double> originValues;

            if (this._argsbWriteOffset + specData.Length > this._argbsPointer.Length)
            {
                //需要移动历史数据位置
                int moveStartIndex = this._argsbWriteOffset + specData.Length - this._imgPixs;
                int moveLen = this._argsbWriteOffset - moveStartIndex;

                var argbsSource = this._argbsPointer.GetSpan(moveStartIndex, moveLen);
                var argbsDest = this._argbsPointer.GetSpan(0, moveLen);
                argbsSource.CopyTo(argbsDest);

                argbs = this._argbsPointer.GetSpan(moveLen, specData.Length);
                if (this._cacheOriginValue)
                {
                    originValues = this._originValuesPointer.GetSpan(moveLen, specData.Length);
                }
                else
                {
                    originValues = this._originValuesPointer.GetSpan(0);
                }

                this._argsbWriteOffset = this._imgPixs;
            }
            else
            {
                //不需要移动历史数据位置
                argbs = this._argbsPointer.GetSpan(this._argsbWriteOffset, specData.Length);
                if (this._cacheOriginValue)
                {
                    originValues = this._originValuesPointer.GetSpan(this._argsbWriteOffset, specData.Length);
                }
                else
                {
                    originValues = this._originValuesPointer.GetSpan(0);
                }

                this._argsbWriteOffset += specData.Length;
            }

            int offset = 0;
            if (this._cacheOriginValue)
            {
                if (this._flipHorizontally)
                {
                    for (int i = 0; i < framCount; i++)
                    {
                        base.PrimitiveAppendData_Flip(specData.Slice(offset, this._fftLength), argbs.Slice(offset, this._fftLength), originValues.Slice(offset, this._fftLength));
                        offset += this._fftLength;
                    }
                }
                else
                {
                    for (int i = 0; i < framCount; i++)
                    {
                        base.PrimitiveAppendData(specData.Slice(offset, this._fftLength), argbs.Slice(offset, this._fftLength), originValues.Slice(offset, this._fftLength));
                        offset += this._fftLength;
                    }
                }
            }
            else
            {
                if (this._flipHorizontally)
                {
                    for (int i = 0; i < framCount; i++)
                    {
                        base.PrimitiveAppendData_Flip(specData.Slice(offset, this._fftLength), argbs.Slice(offset, this._fftLength), originValues);
                        offset += this._fftLength;
                    }
                }
                else
                {
                    for (int i = 0; i < framCount; i++)
                    {
                        base.PrimitiveAppendData(specData.Slice(offset, this._fftLength), argbs.Slice(offset, this._fftLength), originValues);
                        offset += this._fftLength;
                    }
                }
            }

            this._argbsIsUpdated = true;
        }








        /// <summary>
        /// 渲染图
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="rect"></param>
        public void Render(SKCanvas canvas, SKRect rect)
        {
            if (this._argbsIsUpdated)
            {
                this._argbsIsUpdated = false;
                SpanZ<uint> argbs = this._argbsPointer.GetSpanZ();
                this._bitmap.InstallPixels(this._imageInfo, new IntPtr(argbs.DataPtr + this._argsbWriteOffset - this._imgPixs), this._imageInfo.RowBytes, null, null);
            }

            canvas.DrawBitmap(this._bitmap, rect, this._paint);
        }

        /// <summary>
        /// 获取图上指定坐标的值
        /// </summary>
        /// <param name="xIndex">x索引</param>
        /// <param name="yIndex">y索引</param>
        /// <returns>值</returns>
        public double GetValue(int xIndex, int yIndex)
        {
            var index = this._argsbWriteOffset - this._imgPixs + yIndex * this._fftLength + xIndex;
            if (index < 0 || index > this._originValuesPointer.Length)
            {
                return double.NaN;
            }
            else
            {
                return this._originValuesPointer[index];
            }
        }


    }
}
